//
//  ZegoUIKitPrebuiltLiveStreamingVC.swift
//  ZegoUIKit
//
//  Created by zego on 2022/8/26.
//

import UIKit
import IQKeyboardManagerSwift
import SnapKit
import Localize_Swift
import Reusable

extension ZegoUIKitPrebuiltLiveStreamingVC: LiveStreamingVCApi {
    /// 添加自定义按钮到底部菜单栏
    @objc public func addButtonToBottomMenuBar(_ button: UIButton, role: ZegoLiveStreamingRole, position:ZegoLiveBottomMenuBarPosition = .left) {
        self.bottomBar.addButtonToMenuBar(button: button, role: role, position: position)
    }
    
    /// 设置自定义的开始直播按钮
    @objc public func setStartLiveButton(_ button: ZegoStartLiveButton) {
        self.startLiveButton?.removeFromSuperview()
        self.startLiveButton = button
        self.startLiveButton?.delegate = self.help
        self.view.addSubview(self.startLiveButton!)
    }
    
    /// 清空底部菜单栏的扩展按钮
    @objc public func clearBottomMenuBarExtendButtons(_ role: ZegoLiveStreamingRole) {
        self.bottomBar.clearBottomBarExtendButtons(role)
    }
    
    /// 设置自定义背景视图
    @objc public func setBackgroundView(_ view: UIView) {
        self.backgroundView.setCustomBackGroundView(view: view)
    }
    
    /// 离开房间的统一入口
    @objc public func leaveRoom() {
        self.help.onLeaveButtonClick(true)
    }
    
    /// 发送弹幕消息
    @objc public func sendBarrageMessage(roomID: String, message: String, callback: ((Int, String) -> Void)?) {
        ZegoUIKit.shared.sendBarrageMessage(roomID: roomID, message: message) { errorCode, messageID in
            callback?(Int(errorCode),message)
        }
    }
    
}

/// 直播房间控制器
public class ZegoUIKitPrebuiltLiveStreamingVC: UIViewController {
    
    @objc public weak var delegate: ZegoUIKitPrebuiltLiveStreamingVCDelegate?
    //    let inputViewHeight: CGFloat = 55
    
    // 用户基本信息
    var userID: String?
    var userName: String?
    var userAvatar: String?
    var liveID: String?
    
    // MARK: 直播配置
    /// 直播配置（设置时同步更新UI组件）直播间配置 默认观众类型
    var config: ZegoUIKitPrebuiltLiveStreamingConfig = ZegoUIKitPrebuiltLiveStreamingConfig.audience() {
        didSet{
            self.bottomBar.config = config
            self.memberButton.config = config
        }
    }
    
    // MARK: 房间状态相关
    /// 当前主播信息（变化时更新底部工具栏和成员列表）
    var currentHost: ZegoUIKitUser? {
        didSet {
            self.bottomBar.hostID = self.currentHost?.userID
            self.memberButton.currentHost = currentHost
            if self.config.role != .host {
                if currentHost != nil {
                    self.headIconView.isHidden = false
                    self.hostThreeView.isHidden = false
                    self.applyConnectView.isHidden = false
                } else {
                    self.headIconView.isHidden = true
                    self.hostThreeView.isHidden = true
                    self.applyConnectView.isHidden = true
                }
            }
        }
    }
    
    /// 用户在房间内的属性
    var usersInRoomAttributes: [ZegoUserInRoomAttributesInfo]?
    /// 请求连线主播数量
    var requestCoHostCount: Int = 0
    //host
    /// 观众席列表
    var audienceSeatList: [ZegoUIKitUser] = []
    /// 主播邀请列表
    var hostInviteList: [ZegoUIKitUser] = []
    /// 连接主播列表
    var coHostList: [ZegoUIKitUser] = []
    //audience
    /// 观众邀请列表
    var audienceInviteList: [ZegoUIKitUser] = []
    /// 接收的邀请列表
    var audienceReceiveInviteList: [ZegoUIKitUser] = []
    /// 是否显示相机权限提示。
    var isShowCameraPermissionAlter: Bool = false
    /// 是否显示麦克风权限提示
    var isShowMicPermissionAlter: Bool = false
    /// 直播状态（0: 未开始, 1: 进行中）
    var liveStatus: String = "0" {
        didSet {
            self.bottomBar.liveStatus = liveStatus
            self.audioVideoContainer?.view.isHidden = (liveStatus == "1" || self.config.role == .host) ? false : true
            self.backgroundView.liveStatus = liveStatus
        }
    }
    /// 音视频容器
    var audioVideoContainer: ZegoAudioVideoContainer?
    /// PK?
    var pkBattleView: PKContainer?
    
    /// true: 允许翻译, false: 不允许翻译
    var isAllowedTranslation: Bool = true
    
    // MARK: 为了让子类重写, 修改调用
    //----------------------------------------
    /// 处理响应
    internal lazy var help: ZegoUIKitPrebuiltLiveStreamingVC_Help = {
        return createHelp()
    } ()
    func createHelp() -> ZegoUIKitPrebuiltLiveStreamingVC_Help {
        return ZegoUIKitPrebuiltLiveStreamingVC_Help()
    }
    //----------------------------------------
    
    /// 直播间管理
    let liveManager = ZegoLiveStreamingManager.shared
    
    /// 主播实时翻译列表
    var messages: [IMRecvSeiModel] = NSMutableArray() as! [IMRecvSeiModel]
    
    /// 语音转写服务类型：true-科大讯飞，false-阿里（NeoNui）
    var useIFlyASR: Bool = true
    
    /// 科大讯飞实时语音转写管理器
    private var iflyASRManager: IFlyRealTimeASRManager?
    
    // MARK: UI组件声明
    /// 房间提示标签
    lazy var roomTipLabel: UILabel = {
        let label: UILabel = UILabel()
        label.numberOfLines = 0
        label.textAlignment = .center
        label.text = self.config.translationText.noHostOnline
        label.textColor = UIColor.colorWithHexString("#FFFFFF")
        label.font = UIFont.systemFont(ofSize: 14)
        return label
    }()
    /// 背景视图（包含默认背景和自定义背景）
    lazy var backgroundView: ZegoLiveStreamingBackGroundView = {
        let view = ZegoLiveStreamingBackGroundView(frame: CGRectZero, config: self.config)
        return view
    }()
    /// 离开按钮
    lazy var leaveButton: ZegoLeaveButton = {
        let button = ZegoLeaveButton()
        if let confirmDialogInfo = self.config.confirmDialogInfo {
            confirmDialogInfo.dialogPresentVC = self
            button.quitConfirmDialogInfo = confirmDialogInfo
        }
        button.delegate = self.help
        button.iconLeave = ZegoUIKitLiveStreamIconSetType.top_close.load()
        return button
    }()
    /// 返回按钮
    lazy var backButton: UIButton = {
        let button = UIButton()
        button.addTarget(self, action: #selector(backButtonClick), for: .touchUpInside)
        button.setImage(ZegoUIKitLiveStreamIconSetType.icon_comeback.load(), for: .normal)
        return button
    }()
    /// 切换前后摄像头
    lazy var switchCameraButton: UIButton = {
        let button: ZegoSwitchCameraButton = ZegoSwitchCameraButton()
        button.iconFrontFacingCamera = ZegoUIKitLiveStreamIconSetType.icon_nav_flip.load()
        button.iconBackFacingCamera = ZegoUIKitLiveStreamIconSetType.icon_nav_flip.load()
        return button
    }()
    /// 观众人数按钮
    lazy var memberButton: ZegoMemberButton = {
        let button = ZegoMemberButton()
        button.vc = self
        button.delegate = self.help
        button.config = self.config
        return button
    }()
    /// 观众席前三位
    lazy var hostThreeView: ZegoLiveHostThreeListView = {
        let hostThreeView = ZegoLiveHostThreeListView()
        return hostThreeView
    }()
    /// 是否显示小红点
    var showRedDot: Bool = false {
        didSet {
            self.redDot.isHidden = !showRedDot
        }
    }
    
    /// 红点
    lazy var redDot: UIView = {
        let dot = UIView()
        dot.backgroundColor = UIColor.red
        dot.isHidden = true
        return dot
    }()
    /// 底部工具栏
    lazy var bottomBar: ZegoLiveStreamBottomBarType = {
        let bar = ZegoLiveStreamBottomBar()
        bar.userID = userID
        bar.config = self.config
        bar.delegate = self.help
        bar.liveStatus = self.liveStatus
        return bar
    }()
    /// 弹幕消息列表
    lazy var messageView: ZegoInRoomMessageView = {
        let messageList = ZegoInRoomMessageView()
        messageList.delegate = self.help
        return messageList
    }()
    
    /// 实时翻译列表
    lazy var translationView: CallTranslationView = {
        CallTranslationView.loadFromNib()
    }()
    
    //    /// 消息输入视图（处理弹幕消息输入）
    //    lazy var inputTextView: ZegoInRoomMessageInput = {
    //        let messageInputView = ZegoInRoomMessageInput()
    //        messageInputView.frame = CGRect(x: 0, y: UIScreen.main.bounds.size.height, width: UIScreen.main.bounds.size.width, height: inputViewHeight)
    //        return messageInputView
    //    }()
    
    /// 消息输入视图（处理弹幕消息输入）
    fileprivate var keyboardManager: InputBoxManager!
    fileprivate var inputBoxView: IMChatInputBoxView!
    
    
    ///  开始直播按钮
    var startLiveButton: ZegoStartLiveButton?
    /// 直播用户头像
    lazy var headIconView: ZegoLiveHostHeaderView = {
        let iconView = ZegoLiveHostHeaderView()
        return iconView
    }()
    /// 中间 右侧 申请链接 三个框
    lazy var applyConnectView: GZApplyConnectView = {
        let connectView = GZApplyConnectView()
        return connectView
    }()
    /// 直播观众列表
    lazy var liveSpectorListView: LiveSpectatorListView = {
        let lslV = LiveSpectatorListView(frame: CGRectMake(0, 0, xScreenW, xScreenH * 0.6))
        return lslV
    }()
    /// 创建音视频容器
    func createAudioVideoViewContainer() {
        if let _ = audioVideoContainer {
            return
        }
        let container = ZegoAudioVideoContainer()
        audioVideoContainer = container
        container.delegate = self.help
        // 音视频配置
        let audioVideoViewConfig: ZegoAudioVideoViewConfig = ZegoAudioVideoViewConfig()
        audioVideoViewConfig.useVideoViewAspectFill = self.config.audioVideoViewConfig.useVideoViewAspectFill
        audioVideoViewConfig.showSoundWavesInAudioMode = self.config.audioVideoViewConfig.showSoundWavesInAudioMode
        
        if let layout = config.layout {
            if layout.config is ZegoLayoutGalleryConfig {
                let galleryConfig = layout.config as! ZegoLayoutGalleryConfig
                container.setLayout(layout.mode, config: galleryConfig, audioVideoConfig: audioVideoViewConfig)
            } else if layout.config is ZegoLayoutPictureInPictureConfig {
                let pipConfig = layout.config as! ZegoLayoutPictureInPictureConfig
                container.setLayout(layout.mode, config: pipConfig, audioVideoConfig: audioVideoViewConfig)
            }
        } else {
            let layoutConfig = ZegoLayoutPictureInPictureConfig()
            // 修改小窗口的位置
            layoutConfig.smallViewPosition = .bottomRight
            layoutConfig.smallViewSize = CGSize(width: 93, height: 124)
            layoutConfig.spacingBetweenSmallViews = 8
            layoutConfig.removeViewWhenAudioVideoUnavailable = true
            container.setLayout(.pictureInPicture, config: layoutConfig, audioVideoConfig: audioVideoViewConfig)
        }
        container.view.backgroundColor = UIColor.colorWithHexString("#4A4B4D")
        self.view.insertSubview(container.view, at: 0)
    }
    
    /// 销毁音视频view
    func destroyAudioVideoView() {
        audioVideoContainer?.view.removeFromSuperview()
        audioVideoContainer = nil
    }
    /// 创建PKView
    func createPKView() {
        if let _ = pkBattleView {
            return
        }
        let view = PKContainer(frame: CGRect.zero, role: liveManager.currentRole)
        view.delegate = self.help
        pkBattleView = view
        self.view.insertSubview(view, at: 0)
    }
    /// 销毁PVView
    func destroyPKView() {
        pkBattleView?.removeFromSuperview()
        pkBattleView = nil
    }
    /// 初始化直播间
    @objc public init(_ appID: UInt32, appSign: String, userID: String, userName: String, liveID: String, config: ZegoUIKitPrebuiltLiveStreamingConfig) {
        super.init(nibName: nil, bundle: nil)
        debugPrint("your userID:\(userID)")
        
        // 基础参数设置
        self.userID = userID
        self.userName = userName
        self.liveID = liveID
        self.config = config
        
        // 配置视频参数
        ZegoUIKit.shared.setVideoConfig(config: config.videoConfig.resolution)
        let zegoLanguage: ZegoUIKitLanguage = config.translationText.getLanguage()
        // zego 的UI 文本本地化
        let zegoUIKitLanguage = ZegoUIKitLanguage(rawValue: zegoLanguage.rawValue)!
        ZegoUIKitTranslationTextConfig.shared.translationText = ZegoUIKitTranslationText(language: zegoUIKitLanguage);
        
        // 初始化直播管理器
        liveManager.addLiveManagerDelegate(self.help)
        // 初始化
        liveManager.initWithAppID(appID: appID, appSign: appSign, enableSignalingPlugin: config.enableSignalingPlugin)
        
        // 设置代理和初始状态
        ZegoUIKit.shared.addEventHandler(self.help)
        // 如果是主播
        if config.role == .host {
            self.currentHost = ZegoUIKitUser.init(userID, userName)
        }
        // 配置角色
        liveManager.currentRole = config.role
        self.backgroundView.config = config
        self.backgroundView.liveStatus = liveStatus
        self.help.liveStreamingVC = self
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        //  登录并加入房间
        liveManager.login(userID: userID ?? "", userName: userName ?? "", userAvatar: userAvatar ?? "") { data in
            // DispatchQueue.main.async {
                self.setupUI()
            // }
            let code = data?["code"] as! Int
            if code == 0 {
                // 加入直播间
                self.joinRoom()
            }
        }
        
        initCommentInputBarUI()
        updateLanguageAction()
        // 添加键盘监听
        // NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChangeFrame(node:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
        
        /// 监听语言的变化
        NotificationCenter.default.addObserver(self, selector: #selector(updateLanguageAction), name: NSNotification.Name(LCLLanguageChangeNotification), object: nil)
    }
    
    
    /// 初始化UI
    func setupUI() {
        createAudioVideoViewContainer()
        self.view.backgroundColor = UIColor.white
        self.view.addSubview(self.backgroundView)
        self.view.addSubview(self.switchCameraButton)
        self.view.addSubview(self.headIconView)
        self.view.addSubview(self.leaveButton)
        self.view.addSubview(self.memberButton)
        self.view.addSubview(self.hostThreeView)
        self.view.addSubview(self.redDot)
        self.view.addSubview(self.bottomBar)
        // self.view.addSubview(self.inputTextView)
        self.view.addSubview(self.backButton)
        self.view.addSubview(self.applyConnectView)
        view.addSubview(translationView)
        translationView.snp.makeConstraints { make in
            make.left.equalTo(headIconView.snp.left)
            make.top.equalTo(headIconView.snp.bottom).offset(16)
            make.width.equalTo(xScreenW*2/3)
            make.height.lessThanOrEqualTo(xScreenW*2/3)
        }
        
        self.createNormalStartLiveButton()
        if let startLiveButton = startLiveButton {
            self.view.bringSubviewToFront(startLiveButton)
        }
        if let pkBattleView = pkBattleView {
            self.view.insertSubview(pkBattleView, at: 0)
        }
        self.memberButton.currentHost = self.currentHost
        self.setupLayout()
        self.setUIDisplayStatus()
    }
    
    /// 创建开始按钮
    func createNormalStartLiveButton() {
        let button: ZegoStartLiveButton = ZegoStartLiveButton()
        button.delegate = self.help
        button.backgroundColor = UIColor.colorWithHexString("#A754FF")
        button.setTitleColor(UIColor.colorWithHexString("#FFFFFF"), for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
        button.setTitle("开始".localized(.live), for: .normal)
        button.layer.masksToBounds = true
        button.layer.cornerRadius = 22
        self.startLiveButton = button
        self.view.addSubview(self.startLiveButton!)
    }
    /// 设置 UI 显示状态
    func setUIDisplayStatus() {
        if self.config.role == .host {
            self.headIconView.host = ZegoUIKit.shared.localUserInfo
            if liveStatus == "1" {
                // 主播直播中状态
                self.switchCameraButton.isHidden = true
                self.memberButton.isHidden = false
                self.leaveButton.isHidden = false
                self.backButton.isHidden = true
                self.headIconView.isHidden = false
                self.hostThreeView.isHidden = false
                self.applyConnectView.isHidden = false
            } else {
                //  主播未开播状态
                self.switchCameraButton.isHidden = false
                self.memberButton.isHidden = true
                self.leaveButton.isHidden = true
                self.backButton.isHidden = false
                self.headIconView.isHidden = true
                self.hostThreeView.isHidden = true
                self.applyConnectView.isHidden = true
            }
        } else {
            // 观众状态
            self.switchCameraButton.isHidden = true
            self.startLiveButton?.isHidden = true
            if self.currentHost == nil {
                self.headIconView.isHidden = true
                self.hostThreeView.isHidden = true
                self.applyConnectView.isHidden = true
            } else {
                self.headIconView.isHidden = false
                self.hostThreeView.isHidden = false
                self.applyConnectView.isHidden = false
            }
            self.memberButton.isHidden = false
            self.leaveButton.isHidden = false
            self.switchCameraButton.isHidden = true
            self.backButton.isHidden = true
        }
        
    }
    
    public override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.setupLayout()
    }
    
    
    
    //    @objc func keyboardWillChangeFrame(node : Notification) {
    //        print(node.userInfo ?? "")
    //        // 1.获取动画执行的时间
    //        let duration = node.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as! TimeInterval
    //        // 2.获取键盘最终 Y值
    //        let endFrame = (node.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    //        let y = endFrame.origin.y
    //
    //        //3计算工具栏距离底部的间距
    //        let margin = UIScreen.main.bounds.size.height - y
    //        //4.执行动画
    //        UIView.animate(withDuration: duration) { [weak self] in
    //          guard let self = self else { return }
    //
    //            self.view.layoutIfNeeded()
    //            if margin > 0 {
    //                self.inputTextView.frame = CGRect(x: 0, y: UIScreen.main.bounds.size.height - margin - self.inputViewHeight, width: UIScreen.main.bounds.size.width, height: self.inputViewHeight)
    //            } else {
    //                self.inputTextView.frame = CGRect(x: 0, y: UIScreen.main.bounds.size.height - margin, width: UIScreen.main.bounds.size.width, height: self.inputViewHeight)
    //            }
    //
    //        }
    //    }
    
    internal func setupLayout() {
        self.audioVideoContainer?.view.frame = CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height)
        self.backgroundView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height)
        self.headIconView.frame = CGRect(x: 16, y: 53, width: 150, height: 60)
        self.backButton.frame = CGRect(x: 4, y: 50, width: 40, height: 40)
        self.pkBattleView?.frame = CGRect(x: 0, y: 0, width: view.bounds.size.width, height: view.bounds.size.height)
        self.switchCameraButton.frame = CGRect(x: self.view.frame.size.width - 52, y: 52, width: 36, height: 36)
        self.leaveButton.frame = CGRect(x: self.view.frame.size.width - 40, y: 57, width: 30, height: 30)
        //        self.leaveButton.backgroundColor = UIColor.colorWithHexString("#1E2740", alpha: 0.4)
        //        self.leaveButton.layer.masksToBounds = true
        //        self.leaveButton.layer.cornerRadius = 13
        self.memberButton.frame = CGRect(x: self.view.frame.size.width - 40 - 35, y: 56, width: 30, height: 30)
        self.memberButton.layer.masksToBounds = true
        self.memberButton.layer.cornerRadius = 15
        self.memberButton.backgroundColor = UIColor.colorWithHexString("#000000", alpha: 0.3)
        self.hostThreeView.frame = CGRect(x: self.headIconView.frame.maxX + 10, y: 56, width: 100, height: 30)
        self.redDot.frame = CGRect(x: self.memberButton.frame.maxX - 8, y: self.memberButton.frame.minY, width: 8, height: 8)
        self.redDot.layer.masksToBounds = true
        self.redDot.layer.cornerRadius = 4
        self.bottomBar.frame = CGRect(x: 0, y: self.view.frame.size.height - 72, width: self.view.frame.size.width, height: 62)
        // self.messageView.frame = CGRect(x: 16, y: self.view.frame.size.height - 72 - 200, width: UIkitLiveScreenWidth - 16 - 117, height: 200)
        self.startLiveButton?.frame = CGRect(x: (self.view.frame.size.width - 150) / 2, y: self.view.frame.size.height - 44 - 48.5, width: 150, height: 44)
        self.applyConnectView.frame = CGRect(x: self.view.frame.size.width - 100, y: 340, width: 90, height: 290)
    }
    /// 加入直播间
    private func joinRoom() {
        guard let liveID = self.liveID, let userID = self.userID, let userName = self.userName else { return }
        
        // 加入房间
        liveManager.joinRoom(userID: userID, userName: userName, roomID: liveID, markAsLargeRoom: self.config.markAsLargeRoom) {[self] errorCode in
            if errorCode == 0 {
                self.setUsersInRoomAttributesZIM()
            }
        }
        // 检查权限
        if self.config.turnOnCameraWhenJoining || self.config.turnOnMicrophoneWhenJoining {
            self.requestCameraAndMicPermission(true)
        }
        
        ZegoUIKit.shared.turnCameraOn(self.userID ?? "", isOn: self.config.turnOnCameraWhenJoining)
        ZegoUIKit.shared.turnMicrophoneOn(self.userID ?? "", isOn: self.config.turnOnMicrophoneWhenJoining)
        
    }
    
    func onLiveStreamingEnded() {
        dismiss(animated: true)
    }
    
    // 设置用户在房间的属性
    func setUsersInRoomAttributesZIM() {
        /// value 传头像,url 超长了, 报错
        /// code":6000353,
        /// set room members attributes failed with code: 183040, message: user attribute value lenath limit!
        ZegoUIKit.getSignalingPlugin().setUsersInRoomAttributes("avatar", value: "", userIDs: [self.userID!], roomID: self.liveID!) {[self] data in
//        ZegoUIKit.getSignalingPlugin().setUsersInRoomAttributes("avatar", value: self.config.userAvatarUrl ?? "", userIDs: [self.userID!], roomID: self.liveID!) {[self] data in
            guard let data = data else { return }
            let code = data["code"] as! Int
            xLog("[live] login \(data as NSDictionary)")
            if code == 0  {
                print("setUsersInRoomAttributes error: ",code)
                self.queryInRoomUserAttribute()
            }
        }
    }
    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        self.view.endEditing(true)
    }
    
    /// 开始直播点击
    @objc func startLiveClick() {
        //Check the permissions
        GLLiveCoHostManager.shared.removeAll()
        // 检查权限
        if self.isShowCameraPermissionAlter && self.isShowMicPermissionAlter {
            self.setStartLiveStatus()
        } else {
            self.applicationHasMicAndCameraAccess()
        }
    }
    /// 返回按钮点击
    @objc func backButtonClick() {
        
        ZegoUIKit.shared.updateRoomProperties(["live_status": "0", "host": ""]) { data in
            if data?["code"] as! Int == 0 {
                
            }
            self.dismiss(animated: true)
            self.delegate?.onLeaveLiveStreaming?()
        }
    }
    /// 设置开始直播状态
    func setStartLiveStatus() {
        self.liveStatus = "1"
        ZegoUIKit.shared.updateRoomProperties(["host": self.userID ?? "", "live_status": "1"], callback: nil)
        self.startLiveButton?.isHidden = true
        self.bottomBar.isHidden = false
        self.setUIDisplayStatus()
    }
    
    // MARK: 权限管理
    /// 检查音视频权限的统一入口
    func requestCameraAndMicPermission(_ needDelay: Bool = false) {
        var requestCameraEnd: Bool = false
        var requestMicEnd: Bool = false
        
        // 摄像头权限检查
        if !ZegoLiveStreamAuthorizedCheck.isCameraAuthorizationDetermined() {
            requestCameraEnd = false
            //not determined
            ZegoLiveStreamAuthorizedCheck.requestCameraAccess { [weak self] in
                guard let self = self else { return }
                //agree
                requestCameraEnd = true
                self.showCameraOrMicAlter(requestCameraEnd, showMic: requestMicEnd, needDelay: false)
            } cancelCompletion: { [weak self] in
                guard let self = self else { return }
                //disagree
                requestCameraEnd = true
                self.showCameraOrMicAlter(requestCameraEnd, showMic: requestMicEnd, needDelay: false)
            }
        } else {
            requestCameraEnd = true
            self.showCameraOrMicAlter(requestCameraEnd, showMic: requestMicEnd, needDelay: needDelay)
        }
        
        // 麦克风权限检查
        if !ZegoLiveStreamAuthorizedCheck.isMicrophoneAuthorizationDetermined() {
            requestMicEnd = false
            //not determined
            ZegoLiveStreamAuthorizedCheck.requestMicrophoneAccess { [weak self] in
                guard let self = self else { return }
                //agree
                requestMicEnd = true
                self.showCameraOrMicAlter(requestCameraEnd, showMic: requestMicEnd, needDelay: false)
            } cancelCompletion: { [weak self] in
                guard let self = self else { return }
                //disagree
                requestMicEnd = true
                self.showCameraOrMicAlter(requestCameraEnd, showMic: requestMicEnd, needDelay: false)
            }
        } else {
            requestMicEnd = true
            self.showCameraOrMicAlter(requestCameraEnd, showMic: requestMicEnd, needDelay: needDelay)
        }
    }
    
    func showCameraOrMicAlter(_ showCamera: Bool, showMic: Bool, needDelay: Bool) {
        if needDelay {
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                self.delayExecution(showCamera, showMic: showMic)
            }
        } else {
            self.delayExecution(showCamera, showMic: showMic)
        }
    }
    
    func delayExecution(_ showCamera: Bool, showMic: Bool) {
        if showCamera && showMic {
            if !ZegoLiveStreamAuthorizedCheck.isCameraAuthorized() {
                ZegoLiveStreamAuthorizedCheck.showCameraUnauthorizedAlert(self.config.translationText, viewController: self) {
                    ZegoLiveStreamAuthorizedCheck.openAppSettings()
                    if !ZegoLiveStreamAuthorizedCheck.isMicrophoneAuthorized() {
                        ZegoLiveStreamAuthorizedCheck.showMicrophoneUnauthorizedAlert(self.config.translationText, viewController: self) {
                            ZegoLiveStreamAuthorizedCheck.openAppSettings()
                        } cancelCompletion: {
                            
                        }
                    }
                } cancelCompletion: {
                    if !ZegoLiveStreamAuthorizedCheck.isMicrophoneAuthorized() {
                        ZegoLiveStreamAuthorizedCheck.showMicrophoneUnauthorizedAlert(self.config.translationText, viewController: self) {
                            ZegoLiveStreamAuthorizedCheck.openAppSettings()
                        } cancelCompletion: {
                            
                        }
                    }
                }
            } else {
                if !ZegoLiveStreamAuthorizedCheck.isMicrophoneAuthorized() {
                    ZegoLiveStreamAuthorizedCheck.showMicrophoneUnauthorizedAlert(self.config.translationText, viewController: self) {
                        ZegoLiveStreamAuthorizedCheck.openAppSettings()
                    } cancelCompletion: {
                        
                    }
                }
            }
        }
    }
    /// 处理应用程序的麦克风和摄像头权限问题
    fileprivate func applicationHasMicAndCameraAccess() {
        // determined but not authorized
        if !ZegoLiveStreamAuthorizedCheck.isCameraAuthorized() {
            self.isShowCameraPermissionAlter = true
            ZegoLiveStreamAuthorizedCheck.showCameraUnauthorizedAlert(self.config.translationText, viewController: self) {
                ZegoLiveStreamAuthorizedCheck.openAppSettings()
                if !ZegoLiveStreamAuthorizedCheck.isMicrophoneAuthorized() {
                    ZegoLiveStreamAuthorizedCheck.showMicrophoneUnauthorizedAlert(self.config.translationText, viewController: self) {
                        ZegoLiveStreamAuthorizedCheck.openAppSettings()
                    } cancelCompletion: {
                        self.setStartLiveStatus()
                    }
                }
            } cancelCompletion: {
                // determined but not authorized
                self.isShowMicPermissionAlter = true
                if !ZegoLiveStreamAuthorizedCheck.isMicrophoneAuthorized() {
                    ZegoLiveStreamAuthorizedCheck.showMicrophoneUnauthorizedAlert(self.config.translationText, viewController: self) {
                        ZegoLiveStreamAuthorizedCheck.openAppSettings()
                    } cancelCompletion: {
                        self.setStartLiveStatus()
                    }
                } else {
                    self.setStartLiveStatus()
                }
            }
        } else {
            self.isShowCameraPermissionAlter = true
            self.isShowMicPermissionAlter = true
            // determined but not authorized
            if !ZegoLiveStreamAuthorizedCheck.isMicrophoneAuthorized() {
                ZegoLiveStreamAuthorizedCheck.showMicrophoneUnauthorizedAlert(self.config.translationText, viewController: self) {
                    ZegoLiveStreamAuthorizedCheck.openAppSettings()
                } cancelCompletion: {
                    self.setStartLiveStatus()
                }
            } else {
                self.setStartLiveStatus()
            }
        }
        
    }
    
    func updateConfigMenuBar(_ role: ZegoLiveStreamingRole) {
        self.config.role = role
        liveManager.currentRole = role
        self.bottomBar.config = self.config
        //        guard let menuBarButtons = menuBarButtons else {
        //            return
        //        }
        //        var newMenuBarButtons: [ZegoMenuBarButtonName] = []
        //        for buttonName in menuBarButtons {
        //            let buttonType: ZegoMenuBarButtonName? = ZegoMenuBarButtonName(rawValue: buttonName)
        //            if let buttonType = buttonType {
        //                newMenuBarButtons.append(buttonType)
        //            }
        //        }
        //        self.config.bottomMenuBarConfig.buttons = newMenuBarButtons
        //        self.bottomBar.config = self.config
    }
    
    func addOrRemoveSeatListUser(_ user: ZegoUIKitUser, isAdd: Bool) {
        if isAdd {
            self.audienceSeatList.append(user)
        } else {
            self.audienceSeatList = self.audienceSeatList.filter({
                return $0.userID != user.userID
            })
        }
        self.updateRequestCoHost(user, isAdd: isAdd)
        self.memberButton.requestCoHostList = self.audienceSeatList
    }
    
    func addOrRemoveHostInviteList(_ user: ZegoUIKitUser, isAdd: Bool) {
        if isAdd {
            self.hostInviteList.append(user)
        } else {
            self.hostInviteList = self.hostInviteList.filter({
                return $0.userID != user.userID
            })
        }
        self.memberButton.hostInviteList = self.hostInviteList
    }
    
    func addOrRemoveAudienceInviteList(_ user: ZegoUIKitUser, isAdd: Bool) {
        if isAdd {
            self.audienceInviteList.append(user)
        } else {
            self.audienceInviteList.removeAll()
        }
        self.bottomBar.audienceInviteList = self.audienceInviteList
    }
    
    func addOrRemoveAudienceReceiveInviteList(_ user: ZegoUIKitUser, isAdd: Bool) {
        if isAdd {
            self.audienceReceiveInviteList.append(user)
        } else {
            self.audienceReceiveInviteList.removeAll()
        }
    }
    
    func updateRequestCoHost(_ user: ZegoUIKitUser, isAdd: Bool) {
        if isAdd {
            self.requestCoHostCount = self.requestCoHostCount + 1
        } else {
            self.requestCoHostCount = (self.requestCoHostCount - 1) < 0 ? 0 : self.requestCoHostCount - 1
        }
        self.showRedDot = self.requestCoHostCount > 0
    }
    
    ///
    func queryInRoomUserAttribute(){
        ZegoUIKit.getSignalingPlugin().queryUsersInRoomAttributes(ZegoUsersInRoomAttributesQueryConfig()) {[unowned self] data in
            guard let data = data else { return }
            print("queryInRoomUserAttribute data:%@",data)
            if data["code"] as! Int == 0 {
                self.usersInRoomAttributes = data["infos"] as? [ZegoUserInRoomAttributesInfo]
            }
        }
    }
    
    // 更新语言
    @objc private func updateLanguageAction() {
        inputBoxView.inputTextView.placeholder = "说点什么".localized(.live)
        startLiveButton?.setTitle("开始".localized(.live), for: .normal)
    }
    
    
    deinit {
        liveManager.leaveRoom()
        stopRealtimeTranslation()
        // NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
        xLog("ZegoUIKitPrebuiltLiveStreamingVC deinit")
    }
    
}

class ZegoUIKitPrebuiltLiveStreamingVC_Help: NSObject, ZegoAudioVideoContainerDelegate, ZegoUIKitEventHandle, ZegoLiveStreamBottomBarDelegate, LeaveButtonDelegate, ZegoMemberButtonDelegate, ZegoStartLiveButtonDelegate, ZegoLiveStreamingManagerDelegate, PKContainerDelegate, ZegoInRoomMessageViewDelegate {
    
    // 处理协议为实现报错
    func onUserIDUpdated(userID: String) -> String? {
        return userID
    }
    
    
    
    weak var liveStreamingVC: ZegoUIKitPrebuiltLiveStreamingVC?
    var shouldSortHostAtFirst: Bool = true
    weak var invitateAlter: UIAlertController?
    weak var pkAlterView: UIAlertController?
    
    //MARK: -ZegoUIKitEventHandle
    ///用户属性批量更新
    func onUsersInRoomAttributesUpdated(_ updateKeys: [String]?, oldAttributes: [ZegoUserInRoomAttributesInfo]?, attributes: [ZegoUserInRoomAttributesInfo]?, editor: ZegoUIKitUser?) {
        
        guard let attributes = attributes else { return }
        for attribute in attributes {
            if attribute.attributes.keys.contains("role") {
                let oldAttribute = self.liveStreamingVC?.usersInRoomAttributes?.filter({ $0.userID == attribute.userID }).first
                if oldAttribute == nil {
                    self.liveStreamingVC?.usersInRoomAttributes?.append(attribute)
                } else {
                    oldAttribute?.attributes = attribute.attributes
                }
            }
        }
        
    }
    /// 房间状态变化（连接中/已连接/断开等）
    func onRoomStateChanged(_ reason: ZegoUIKitRoomStateChangedReason, errorCode: Int32, extendedData: [AnyHashable : Any], roomID: String) {
        guard let liveStreamingVC = liveStreamingVC,
              let userID = liveStreamingVC.userID
        else {
            return
        }
        if reason == .logined {
            if liveStreamingVC.config.role == .host {
                // set room proporty
                liveStreamingVC.liveStatus = "0"
                let roomProperties: [String : String] = ["live_status" : "0", "host" : userID]
                ZegoUIKit.shared.updateRoomProperties(roomProperties, callback: nil)
                liveStreamingVC.bottomBar.isHidden = true
            }
        } else if reason == .reconnected {
            self.liveStreamingVC?.queryInRoomUserAttribute()
        }
    }
    /// 自己被移出房间（管理员操作)
    func onMeRemovedFromRoom() {
        self.onLeaveButtonClick(true)
    }
    
    /// 音视频流可用通知
    func onAudioVideoAvailable(_ userList: [ZegoUIKitUser]) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        for user in userList {
            var isOldUser: Bool = false
            for oldUser in liveStreamingVC.coHostList {
                if oldUser.userID == user.userID {
                    isOldUser = true
                    break
                }
            }
            if !isOldUser {
                liveStreamingVC.coHostList.append(user)
            }
        }
        //        if liveStreamingVC.coHostList.count > 0 && liveStreamingVC.liveStatus == "1" {
        //            liveStreamingVC.backgroundImageView.isHidden = true
        //        }
        liveStreamingVC.memberButton.coHostList = liveStreamingVC.coHostList
    }
    
    /// 音视频流不可用（连接中断或主动关闭）
    func onAudioVideoUnavailable(_ userList: [ZegoUIKitUser]) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        for user in userList {
            if user.userID == liveStreamingVC.currentHost?.userID {
                shouldSortHostAtFirst = true
            }
            var index: Int = 0
            for coHost in liveStreamingVC.coHostList {
                if coHost.userID == user.userID {
                    liveStreamingVC.coHostList.remove(at: index)
                    break
                }
                index = index + 1
            }
            liveStreamingVC.addOrRemoveSeatListUser(user, isAdd: false)
            liveStreamingVC.addOrRemoveHostInviteList(user, isAdd: false)
        }
        //        if liveStreamingVC.coHostList.count == 0 && liveStreamingVC.liveStatus != "1" {
        //            liveStreamingVC.backgroundImageView.isHidden = false
        //        }
        liveStreamingVC.memberButton.coHostList = liveStreamingVC.coHostList
        xLog("音视频流不可用 某人断开连麦")
        GLLiveCoHostManager.shared.filterCoHose(list: liveStreamingVC.coHostList.map({ $0.userID ?? "" }))
        
    }
    
    /// 全量房间属性更新（批量更新时触发）
    func onRoomPropertiesFullUpdated(_ updateKeys: [String], oldProperties: [String : String], properties: [String : String]) {
        guard let liveStreamingVC = liveStreamingVC,
              let _ = liveStreamingVC.userID
        else { return }
        if liveStreamingVC.config.role == .host {
            //            var thereIsHostInRoom: Bool = false
            //            for key in updateKeys {
            //                let value: String? = properties[key]
            //                if key == "host" && value != nil && value != "" && value != userID {
            //                    thereIsHostInRoom = true
            //                    break
            //                }
            //            }
            //            if thereIsHostInRoom {
            //                liveStreamingVC.updateHostProporty(false)
            //            } else {
            //                // start live
            //
            //            }
        } else {
            guard let live_status = properties["live_status"] else { return }
            liveStreamingVC.liveStatus = live_status
            if live_status == "1" {
                
            } else {
                liveStreamingVC.coHostList.removeAll()
                liveStreamingVC.memberButton.coHostList = liveStreamingVC.memberButton.coHostList
            }
        }
    }
    
    /// 单个房间属性更新（键值对变更）
    func onRoomPropertyUpdated(_ key: String, oldValue: String, newValue: String) {
        if key == "host" {
            self.liveStreamingVC?.currentHost = ZegoUIKit.shared.getUser(newValue)
            self.liveStreamingVC?.headIconView.host = self.liveStreamingVC?.currentHost
            self.liveStreamingVC?.audioVideoContainer?.reload()
        } else if key == "live_status" {
            if newValue == "0" {
                shouldSortHostAtFirst = true
                if oldValue == "1" {
                    ZegoUIKit.shared.turnCameraOn(self.liveStreamingVC?.userID ?? "", isOn: false)
                    ZegoUIKit.shared.turnMicrophoneOn(self.liveStreamingVC?.userID ?? "", isOn: false)
                    self.liveStreamingVC?.bottomBar.isCoHost = false
                    self.liveStreamingVC?.delegate?.onLiveStreamingEnded?()
                    self.liveStreamingVC?.onLiveStreamingEnded()
                    if self.liveStreamingVC?.config.role == .coHost {
                        self.liveStreamingVC?.updateConfigMenuBar(.audience)
                    }
                }
                ZegoUIKit.shared.stopPlayingAllAudioVideo()
            } else if newValue == "1" {
                ZegoUIKit.shared.startPlayingAllAudioVideo()
            } else {
                ZegoUIKit.shared.stopPlayingAllAudioVideo()
            }
        }
    }
    
    
    
    
    /// 收到开启摄像头请求（连麦场景）
    func onTurnOnYourCameraRequest(_ fromUser: ZegoUIKitUser) {
        guard let liveStreamingVC = liveStreamingVC,
              let userID = liveStreamingVC.userID
        else { return }
        if liveStreamingVC.config.canCameraTurnOnByOthers {
            if let dialogInfo = liveStreamingVC.config.turnOnYourCameraConfirmDialogInfo {
                let title = dialogInfo.title?.replacingOccurrences(of: "%@", with: fromUser.userName ?? "")
                let message = dialogInfo.message?.replacingOccurrences(of: "%@", with: fromUser.userName ?? "")
                let alterVC: UIAlertController = UIAlertController.init(title: title, message: message, preferredStyle: .alert)
                let sureButton: UIAlertAction = UIAlertAction.init(title: dialogInfo.confirmButtonName, style: .default) { action in
                    ZegoUIKit.shared.turnCameraOn(userID, isOn: true)
                }
                let refuseButton: UIAlertAction = UIAlertAction.init(title: dialogInfo.cancelButtonName, style: .cancel) { action in
                    
                }
                alterVC.addAction(refuseButton)
                alterVC.addAction(sureButton)
                liveStreamingVC.present(alterVC, animated: false)
            } else {
                ZegoUIKit.shared.turnCameraOn(userID, isOn: true)
            }
        }
    }
    
    /// 收到开启麦克风请求（连麦场景）
    func onTurnOnYourMicrophoneRequest(_ fromUser: ZegoUIKitUser) {
        guard let liveStreamingVC = liveStreamingVC,
              let userID = liveStreamingVC.userID
        else { return }
        if liveStreamingVC.config.canMicrophoneTurnOnByOthers {
            if let dialogInfo = liveStreamingVC.config.turnOnYourMicrophoneConfirmDialogInfo {
                let title = dialogInfo.title?.replacingOccurrences(of: "%@", with: fromUser.userName ?? "")
                let message = dialogInfo.message?.replacingOccurrences(of: "%@", with: fromUser.userName ?? "")
                let alterVC: UIAlertController = UIAlertController.init(title: title, message: message, preferredStyle: .alert)
                let sureButton: UIAlertAction = UIAlertAction.init(title: dialogInfo.confirmButtonName, style: .default) { action in
                    ZegoUIKit.shared.turnMicrophoneOn(userID, isOn: true)
                }
                let refuseButton: UIAlertAction = UIAlertAction.init(title: dialogInfo.cancelButtonName, style: .cancel) { action in
                    
                }
                alterVC.addAction(refuseButton)
                alterVC.addAction(sureButton)
                liveStreamingVC.present(alterVC, animated: false)
            } else {
                ZegoUIKit.shared.turnMicrophoneOn(userID, isOn: true)
            }
        }
    }
    
    /// 直播离开弹窗
    func showHostLeaveAlter() {
        let alter: UIAlertController = UIAlertController.init(title: "Attention", message: "The live is over", preferredStyle: .alert)
        let closeButton: UIAlertAction = UIAlertAction.init(title: "Close", style: .default) { action in
            self.liveStreamingVC?.dismiss(animated: true, completion: nil)
        }
        alter.addAction(closeButton)
        if let liveStreamingVC = liveStreamingVC {
            liveStreamingVC.present(alter, animated: false, completion: nil)
        }
    }
    
    /// 当接收到连麦申请请求时调用此方法
    func onIncomingCohostRequest(inviter: ZegoUIKitUser) {
        if liveStreamingVC?.liveManager.currentRole == .host {
            liveStreamingVC?.addOrRemoveSeatListUser(inviter, isAdd: true)
        }
    }
    
    /// 当接收到邀请连麦的请求时调用此方法
    func onIncomingInviteToCohostRequest(inviter: ZegoUIKitUser, invitationID: String) {
        guard let userID = inviter.userID else { return }
        liveStreamingVC?.addOrRemoveAudienceReceiveInviteList(inviter, isAdd: true)
        self.showInvitationAlert(userID, invitationID: invitationID)
    }
    
    /// 当接收到移除连麦者的请求时调用此方法
    func onIncomingRemoveCohostRequest(inviter: ZegoUIKitUser) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        liveStreamingVC.addOrRemoveAudienceInviteList(inviter, isAdd: false)
        liveStreamingVC.addOrRemoveAudienceReceiveInviteList(inviter, isAdd: false)
        liveStreamingVC.bottomBar.isCoHost = false
        ZegoUIKit.shared.turnCameraOn(liveStreamingVC.userID ?? "", isOn: false)
        ZegoUIKit.shared.turnMicrophoneOn(liveStreamingVC.userID ?? "", isOn: false)
        liveStreamingVC.updateConfigMenuBar(.audience)
        // 断开
        xLog("断开连麦状态")
        liveStreamingVC.stopRealtimeTranslation()
        
    }
    
    /// 弹幕消息接收（高并发场景优化）
    func onIMRecvBarrageMessage(_ roomID: String, messageList: [ZegoUIKitBarrageMessageInfo]) {
        self.liveStreamingVC?.delegate?.onIMRecvBarrageMessage?(roomID, messageList: messageList)
    }
    
    /// 显示 tip
    func showTipView(_ tipStr: String) {
        ZegoLiveStreamTipView.showTip(tipStr,onView: liveStreamingVC?.view)
    }
    
    /// 显示邀请弹窗
    func showInvitationAlert(_ inviterID: String, invitationID: String?) {
        guard let liveStreamingVC = liveStreamingVC else {
            return
        }
        let title: String = liveStreamingVC.config.translationText.receivedCoHostInvitationDialogInfoTitle
        let message: String = liveStreamingVC.config.translationText.receivedCoHostInvitationDialogInfoMessage
        let cancelStr: String = liveStreamingVC.config.translationText.receivedCoHostInvitationDialogInfoCancel
        let sureStr: String = liveStreamingVC.config.translationText.receivedCoHostInvitationDialogInfoConfirm
        
        let alterView: UIAlertController = UIAlertController.init(title: title, message: message, preferredStyle: .alert)
        self.invitateAlter = alterView
        let cancelButton: UIAlertAction = UIAlertAction.init(title: cancelStr, style: .cancel) { action in
            let dataDict: [String : AnyObject] = ["invitationID": invitationID as AnyObject]
            if liveStreamingVC.config.enableSignalingPlugin {
                ZegoLiveStreamingManager.shared.getSignalingPlugin()?.refuseInvitation(inviterID, data: dataDict.live_jsonString)
            }
            liveStreamingVC.addOrRemoveAudienceReceiveInviteList(ZegoUIKitUser.init(inviterID, ""), isAdd: false)
        }
        
        let sureButton: UIAlertAction = UIAlertAction.init(title: sureStr, style: .default) { action in
            liveStreamingVC.requestCameraAndMicPermission()
            liveStreamingVC.bottomBar.isCoHost = true
            liveStreamingVC.updateConfigMenuBar(.coHost)
            ZegoUIKit.shared.turnCameraOn(liveStreamingVC.userID ?? "", isOn: true)
            ZegoUIKit.shared.turnMicrophoneOn(liveStreamingVC.userID ?? "", isOn: true)
            if liveStreamingVC.config.enableSignalingPlugin {
                ZegoLiveStreamingManager.shared.getSignalingPlugin()?.acceptInvitation(inviterID, data: nil, callback: nil)
            }
        }
        alterView.addAction(cancelButton)
        alterView.addAction(sureButton)
        liveStreamingVC.present(alterView, animated: false, completion: nil)
        // 一分钟后隐藏视图
        DispatchQueue.main.asyncAfter(deadline: .now() + 60) {
            self.invitateAlter?.dismiss(animated: false)
        }
    }
    
    /// 当连麦申请被接受时调用此方法
    func onIncomingAcceptCohostRequest(invitee: ZegoUIKitUser, data: String?) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        if liveStreamingVC.config.role != .host {
            // is host accept
            // update bottom bar button
            liveStreamingVC.requestCameraAndMicPermission()
            liveStreamingVC.bottomBar.isCoHost = true
            liveStreamingVC.updateConfigMenuBar(.coHost)
            ZegoUIKit.shared.turnCameraOn(liveStreamingVC.userID ?? "", isOn: true)
            ZegoUIKit.shared.turnMicrophoneOn(liveStreamingVC.userID ?? "", isOn: true)
            
            xLog("当连麦申请被接受时调用此方法")
            // 主播同意连麦，打开实时翻译
            liveStreamingVC.startRealtimeTranslation()
        }
    }
    
    /// 当连麦申请被取消时调用此方法
    func onIncomingCancelCohostRequest(inviter: ZegoUIKitUser, data: String?) {
        guard let liveStreamingVC = liveStreamingVC else {
            return
        }
        liveStreamingVC.addOrRemoveSeatListUser(inviter, isAdd: false)
    }
    
    /// 当邀请连麦被取消时调用此方法
    func onIncomingCancelCohostInvite(inviter: ZegoUIKitUser, data: String?) {
        guard let liveStreamingVC = liveStreamingVC else {
            return
        }
        self.invitateAlter?.dismiss(animated: false)
        liveStreamingVC.addOrRemoveAudienceReceiveInviteList(inviter, isAdd: false)
    }
    
    /// 当邀请连麦被拒绝时调用此方法
    func onIncomingRefuseCohostInvite(invitee: ZegoUIKitUser, data: String?) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        let user: ZegoUIKitUser? = ZegoUIKit.shared.getUser(invitee.userID ?? "")
        guard let user = user else { return }
        ZegoLiveStreamTipView.showWarn(String(format: "%@ %@", user.userName ?? "",liveStreamingVC.config.translationText.audienceRejectInvitationToast), onView: liveStreamingVC.view)
        liveStreamingVC.addOrRemoveSeatListUser(invitee, isAdd: false)
        liveStreamingVC.addOrRemoveHostInviteList(invitee, isAdd: false)
    }
    
    /// 当连麦申请被拒绝时调用此方法
    func onIncomingRefuseCohostRequest(invitee: ZegoUIKitUser, data: String?) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        liveStreamingVC.addOrRemoveAudienceInviteList(invitee, isAdd: false)
        ZegoLiveStreamTipView.showWarn(liveStreamingVC.config.translationText.hostRejectCoHostRequestToast, onView: liveStreamingVC.view)
        liveStreamingVC.updateConfigMenuBar(.audience)
    }
    
    /// 当邀请连麦超时未得到响应时调用此方法
    func onIncomingCohostInviteTimeOut(inviter: ZegoUIKitUser, data: String?) {
        guard let liveStreamingVC = liveStreamingVC else {
            return
        }
        liveStreamingVC.addOrRemoveSeatListUser(inviter, isAdd: false)
    }
    
    /// 当邀请连麦超时未得到响应时调用此方法
    func onIncomingCohostRequestTimeOut(inviter: ZegoUIKitUser, data: String?) {
        guard let liveStreamingVC = liveStreamingVC else {
            return
        }
        liveStreamingVC.addOrRemoveAudienceReceiveInviteList(inviter, isAdd: false)
    }
    
    /// 当邀请连麦的响应超时未返回时调用此方法
    func onIncomingCohostInviteResponseTimeOut(invitees: [ZegoUIKitUser], data: String?) {
        guard let liveStreamingVC = liveStreamingVC else {
            return
        }
        for invitee in invitees {
            liveStreamingVC.addOrRemoveHostInviteList(invitee, isAdd: false)
        }
    }
    
    /// 当连麦申请的响应超时未返回时调用此方法
    func onIncomingCohostRequestResponseTimeOut(invitees: [ZegoUIKitUser], data: String?) {
        guard let liveStreamingVC = liveStreamingVC else {
            return
        }
        for invitee in invitees {
            liveStreamingVC.addOrRemoveAudienceInviteList(invitee, isAdd: false)
        }
        liveStreamingVC.bottomBar.isCoHost = false
        liveStreamingVC.updateConfigMenuBar(.audience)
    }
    
    
    //MARK: -ZegoAudioVideoContainerDelegate
    
    /// 获取自定义前景视图（用户头像、标签等）
    func getForegroundView(_ userInfo: ZegoUIKitUser?) -> ZegoBaseAudioVideoForegroundView? {
        if let foregroundView = self.liveStreamingVC?.delegate?.getForegroundView?(userInfo) {
            return foregroundView
        } else {
            // user nomal foregroundView
            let nomalForegroundView: ZegoLiveNomalForegroundView = ZegoLiveNomalForegroundView(frame: .zero, userID: userInfo?.userID, delegate: nil)
            nomalForegroundView.userInfo = userInfo
            return nomalForegroundView
        }
    }
    
    /// 自定义用户列表排序规则
    func sortAudioVideo(_ userList: [ZegoUIKitUser]) -> [ZegoUIKitUser]? {
        if shouldSortHostAtFirst && userList.contains(where: {
            return $0.userID == liveStreamingVC?.currentHost?.userID
        }) {
            var tempList = userList
            var index: Int = 0
            for user in tempList {
                if user.userID == self.liveStreamingVC?.currentHost?.userID {
                    let host = user
                    tempList.remove(at: index)
                    tempList.insert(host, at: 0)
                    break
                }
                index = index + 1
            }
            self.shouldSortHostAtFirst = false
            return tempList
        }
        return userList
    }
    
    //MARK: -ZegoLiveStreamBottomBarDelegate
    /// 点击更多按钮时触发
    func onMenuBarMoreButtonClick(_ buttonList: [UIView]) {
        let newList:[UIView] = buttonList
        let vc: ZegoLiveStreamMoreView = ZegoLiveStreamMoreView()
        vc.buttonList = newList
        self.liveStreamingVC?.view.addSubview(vc.view)
        self.liveStreamingVC?.addChild(vc)
    }
    /// 点击聊天消息按钮
    func onInRoomMessageButtonClick() {
        // self.liveStreamingVC?.inputTextView.startEdit()
        self.liveStreamingVC?.inputBoxView.setTextViewFirstResponder(true)
    }
    /// 连麦控制按钮点击事件
    func coHostControlButtonDidClick(_ type: CoHostControlButtonType, sender: ZegoCoHostControlButton) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        
        /// 初始化 连麦者翻译状态
        liveStreamingVC.isAllowedTranslation = true
        
        switch type {
        case .requestCoHost:
            if liveStreamingVC.liveStatus == "0" {
                ZegoLiveStreamTipView.showWarn(liveStreamingVC.config.translationText.requestCoHostFailed, onView: liveStreamingVC.view)
            } else if liveStreamingVC.liveStatus == "1" {
                guard let host = liveStreamingVC.currentHost else { return }
                if liveStreamingVC.pkBattleView?.isHidden == false {
                    //FIXME: You are not allowed to apply for a link in pk
                    ZegoLiveStreamTipView.showWarn(liveStreamingVC.config.translationText.pkingNotRequestCoHost, onView: liveStreamingVC.view)
                    sender.buttonType = .requestCoHost
                    return
                }
                ZegoLiveStreamTipView.showTip(liveStreamingVC.config.translationText.sendRequestCoHostToast, onView: liveStreamingVC.view)
                liveStreamingVC.addOrRemoveAudienceInviteList(host, isAdd: true)
                if liveStreamingVC.config.enableSignalingPlugin {
                    ZegoLiveStreamingManager.shared.getSignalingPlugin()?.sendInvitation([host.userID ?? ""], timeout: 60, type: ZegoLiveInvitationType.requestCoHost.rawValue, data: nil, notificationConfig: nil) { data in
                        guard let data = data else { return }
                        if data["code"] as! Int != 0 {
                            ZegoLiveStreamTipView.showWarn(liveStreamingVC.config.translationText.requestCoHostFailed, onView: liveStreamingVC.view)
                        } else {
                            sender.buttonType = .cancelCoHost
                        }
                    }
                }
            }
        case .cancelCoHost:
            guard let host = liveStreamingVC.currentHost else { return }
            liveStreamingVC.addOrRemoveAudienceInviteList(host, isAdd: false)
            liveStreamingVC.bottomBar.isCoHost = false
            if liveStreamingVC.config.enableSignalingPlugin {
                ZegoLiveStreamingManager.shared.getSignalingPlugin()?.cancelInvitation([host.userID ?? ""], data: nil, callback: nil)
            }
        case .endCoHost:
            self.showEndConnectionAlter(sender)
        }
    }
    
    /// 显示结束连线 Alert
    func showEndConnectionAlter(_ sender: ZegoCoHostControlButton) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        let alterView: UIAlertController = UIAlertController.init(title: liveStreamingVC.config.translationText.endConnectionDialogInfoTitle, message: liveStreamingVC.config.translationText.endConnectionDialogInfoMessage, preferredStyle: .alert)
        self.invitateAlter = alterView
        let cancelButton: UIAlertAction = UIAlertAction.init(title: liveStreamingVC.config.translationText.cancelMenuDialogButton, style: .cancel) { action in
        }
        
        let sureButton: UIAlertAction = UIAlertAction.init(title: liveStreamingVC.config.translationText.dialogOkText, style: .default) { action in
            sender.buttonType = .requestCoHost
            self.endCohostRequest()
        }
        alterView.addAction(cancelButton)
        alterView.addAction(sureButton)
        liveStreamingVC.present(alterView, animated: false, completion: nil)
    }
    
    /// 结束连线请求
    func endCohostRequest() {
        guard let liveStreamingVC = liveStreamingVC,
              let host = liveStreamingVC.currentHost,
              let userID = liveStreamingVC.userID else { return }
        liveStreamingVC.addOrRemoveAudienceInviteList(host, isAdd: false)
        liveStreamingVC.addOrRemoveAudienceReceiveInviteList(host, isAdd: false)
        liveStreamingVC.bottomBar.isCoHost = false
        ZegoUIKit.shared.turnCameraOn(userID, isOn: false)
        ZegoUIKit.shared.turnMicrophoneOn(userID, isOn: false)
        liveStreamingVC.updateConfigMenuBar(.audience)
    }
    
    //MARK: - LeaveButtonDelegate ZegoLiveStreamBottomBarDelegate
    /// 离开按钮点击
    func onLeaveButtonClick(_ isLeave: Bool) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        if isLeave {
            if liveStreamingVC.config.role == .host {
                var cancelList: [String] = []
                for user in liveStreamingVC.hostInviteList {
                    cancelList.append(user.userID ?? "")
                    if liveStreamingVC.config.enableSignalingPlugin {
                        ZegoLiveStreamingManager.shared.getSignalingPlugin()?.cancelInvitation(cancelList, data: nil, callback: nil)
                    }
                }
                liveStreamingVC.stopRealtimeTranslation()
                
            } else {
                if liveStreamingVC.config.enableSignalingPlugin {
                    ZegoLiveStreamingManager.shared.getSignalingPlugin()?.cancelInvitation([liveStreamingVC.currentHost?.userID ?? ""], data: nil, callback: nil)
                }
            }
            
            if liveStreamingVC.config.role == .host  {
                if liveStreamingVC.liveStatus == "1" {
                    self.liveStreamingVC?.delegate?.onLiveStreamingEnded?()
                    self.liveStreamingVC?.onLiveStreamingEnded()
                }
                ZegoUIKit.shared.updateRoomProperties(["live_status": "0", "host": ""]) { data in
                    if data?["code"] as! Int == 0 {
                        
                    }
                }
            }
            self.liveStreamingVC?.dismiss(animated: true, completion: {
                if liveStreamingVC.config.role == .host  {
                    currentViewController()?.push(LiveNotesController(liveStreamingVC.liveID!))
                }
            })
            self.liveStreamingVC?.delegate?.onLeaveLiveStreaming?()
        }
        
    }
    
    //MARK: -ZegoMemberButtonDelegate
    /// 同意用户连麦请求
    func memberListDidClickAgree(_ user: ZegoUIKitUser) {
        liveStreamingVC?.updateRequestCoHost(user, isAdd: false)
    }
    /// 拒绝用户连麦请求
    func memberListDidClickDisagree(_ user: ZegoUIKitUser) {
        self.liveStreamingVC?.addOrRemoveSeatListUser(user, isAdd: false)
    }
    /// 邀请用户连麦
    func memberListDidClickInvitate(_ user: ZegoUIKitUser) {
        guard let liveStreamingVC = liveStreamingVC else {
            return
        }
        liveStreamingVC.addOrRemoveHostInviteList(user, isAdd: true)
    }
    /// 移除当前连麦用户
    func memberListDidClickRemoveCoHost(_ user: ZegoUIKitUser) {
        
    }
    
    //MARK: - ZegoStartLiveButtonDelegate
    /// 开始按钮点击事件
    func onStartLiveButtonPressed() {
        guard let liveStreamingVC = liveStreamingVC else { return }
        liveStreamingVC.startLiveClick()
        liveStreamingVC.delegate?.onStartLiveButtonPressed?()
        // 开启实时翻译功能
        liveStreamingVC.startRealtimeTranslation()
    }
    
    //MARK: - ZegoLiveStreamingManagerDelegate
    /// 当接收到 PK 请求时调用此方法
    func onIncomingPKRequestReceived(requestID: String, anotherHostUser: ZegoUIKitUser, anotherHostLiveID: String, customData: String?) {
        let alterView = UIAlertController(title: "receive pk request", message: "", preferredStyle: .alert)
        self.pkAlterView = alterView
        let acceptButton: UIAlertAction = UIAlertAction(title: "accept", style: .default) { [weak self] action in
            self?.liveStreamingVC?.liveManager.acceptIncomingPKBattleRequest(requestID, anotherHostLiveID: anotherHostLiveID, anotherHostUser: anotherHostUser)
        }
        let rejectButton: UIAlertAction = UIAlertAction(title: "reject", style: .cancel) { [weak self] action in
            self?.liveStreamingVC?.liveManager.rejectPKBattleStartRequest(requestID)
        }
        alterView.addAction(acceptButton)
        alterView.addAction(rejectButton)
        liveStreamingVC?.present(alterView, animated: true)
    }
    /// 当 PK 请求被取消时调用此方法
    func onIncomingPKRequestCancelled(anotherHostLiveID: String, anotherHostUser: ZegoUIKitUser, customData: String?) {
        self.pkAlterView?.dismiss(animated: true)
    }
    /// 当接收到的 PK 请求超时未得到处理时调用此方法
    func onIncomingPKRequestTimeout(requestID: String, anotherHostUser: ZegoUIKitUser) {
        self.pkAlterView?.dismiss(animated: true)
    }
    /// 当 PK 对战开始时调用此方法
    func onPKStarted(roomID: String, userID: String) {
        guard let liveStreamingVC = liveStreamingVC else { return }
        liveStreamingVC.createPKView()
        if liveStreamingVC.liveManager.currentRole == .host {
            liveStreamingVC.setStartLiveStatus()
            liveStreamingVC.destroyAudioVideoView()
            liveStreamingVC.pkBattleView?.isHidden = false
        } else {
            liveStreamingVC.pkBattleView?.isHidden = true
        }
        liveStreamingVC.pkBattleView?.pkInfo = liveStreamingVC.liveManager.pkInfo
        if liveStreamingVC.liveManager.currentRole == .coHost {
            endCohostRequest()
        } else if liveStreamingVC.liveManager.currentRole == .audience {
            invitateAlter?.dismiss(animated: true)
            if liveStreamingVC.audienceInviteList.count > 0 {
                guard let host = liveStreamingVC.currentHost else { return }
                liveStreamingVC.addOrRemoveAudienceInviteList(host, isAdd: false)
                liveStreamingVC.bottomBar.isCoHost = false
                if liveStreamingVC.config.enableSignalingPlugin {
                    ZegoLiveStreamingManager.shared.getSignalingPlugin()?.cancelInvitation([host.userID ?? ""], data: nil, callback: nil)
                }
            }
        }
    }
    /// 当 PK 对战结束时调用此方法
    func onPKEnded() {
        liveStreamingVC?.pkBattleView?.pkInfo = nil
        liveStreamingVC?.destroyPKView()
        liveStreamingVC?.createAudioVideoViewContainer()
    }
    /// 当 PK 视图可用时调用此方法
    func onPKViewAvaliable() {
        if liveStreamingVC?.liveManager.currentRole != .host {
            liveStreamingVC?.destroyAudioVideoView()
            liveStreamingVC?.pkBattleView?.isHidden = false
        }
    }
    /// 当混流任务失败时调用此方法
    func onMixerStreamTaskFail(errorCode: Int) {
        
    }
    
    //MARK: - PKContainerDelegate
    /// 获取PK前景视图（用于展示单个用户画面）
    func getPKBattleForegroundView(_ parentView: UIView, userInfo: ZegoUIKitUser) -> UIView {
        return liveStreamingVC?.delegate?.getPKBattleForegroundView?(parentView, userInfo: userInfo) ?? UIView()
    }
    /// 获取PK顶部视图（展示双方主播信息）
    func getPKBattleTopView(_ parentView: UIView, userList: [ZegoUIKitUser]) -> UIView {
        return liveStreamingVC?.delegate?.getPKBattleTopView?(parentView, userList: userList) ?? UIView()
    }
    /// 获取PK底部控制栏（包含操作按钮）
    func getPKBattleBottomView(_ parentView: UIView, userList: [ZegoUIKitUser]) -> UIView {
        return liveStreamingVC?.delegate?.getPKBattleBottomView?(parentView, userList: userList) ?? UIView()
    }
    
    // MARK: Message
    /// 当用户点击某条聊天消息时触发
    func onInRoomMessageClick(_ message: ZegoInRoomMessage) {
        liveStreamingVC?.delegate?.onInRoomMessageClick?(message)
    }
    
    public func onPlayerRecvSEI(_ seiString: String, streamID: String) {
        xLog("接收 sei \(seiString)")
        
        if let seiDic = seiString.toDictionary(), let type = seiDic["type"] as? String, type == "5" {
            if let userId = seiDic["userID"] as? String, userId
                == String(UserProfile.userId) {
                // 收到开关翻译的消息
                if let isOn = seiDic["isOn"] as? Int {
                    xLog("收到开关翻译的信号, \(isOn == 1 ? "开": "关")")
                    liveStreamingVC?.isAllowedTranslation = isOn.toBool
                }
            }
        }
        
        ZegoUIKit.shared.sendInRoomMessage(seiString) { errorCode in
            xLog("发送消息 :\(seiString) errorCode: \(errorCode)")
        }
    }
    
    /// 用户麦克风状态变化
    /// - 典型应用: 显示麦克风图标状态
    public func onMicrophoneOn(_ user: ZegoUIKitUser, isOn: Bool) {
        xLog("[onMicrophoneOn] 用户: \(user.userName ?? ""), isOn: \(isOn ? "开": "关")")
        DispatchQueue.global().async {
            /// 异步线程
            if user.userID == String(UserProfile.userId) {
                // 我自己关闭麦克风
                if isOn {
                    NeoNuiManager.shared().startNeoNui()
                } else {
                    NeoNuiManager.shared().pauseNeoNui()
                }
            }
        }
    }
    
    
    func onInRoomMessageReceived(_ messageList: [ZegoInRoomMessage]) {
        if let message = messageList.last {
            if let msgDic = message.message?.toDictionary(), let seiModel = JsonUtil.modelFromDictionary(msgDic, IMRecvSeiModel.self) {
                // xLog("[sei] 收到的消息 \(msgDic)")
                liveStreamingVC?.translationView.updateContent(number: liveStreamingVC?.coHostList.count ?? 1, hostId: liveStreamingVC?.currentHost?.userID ?? "", model: seiModel)
            }
        }
    }
}


// MARK: - IMChatInputBoxView
extension ZegoUIKitPrebuiltLiveStreamingVC {
    
    private func initCommentInputBarUI() {
        inputBoxView = IMChatInputBoxView()
        inputBoxView.frame = CGRect(x: 0, y: 0, width: xScreenW, height: xInputBoxViewMinHeight)
        inputBoxView.delegate = self
        inputBoxView.inputTextView.placeholder = "说点什么".localized(.live)
        
        // keyboard管理类，用来管理键盘，各大面板的切换
        keyboardManager = InputBoxManager(viewController: self)
        // 因为addBottomInputBarView方法会立刻触发delegate，所以这里需要先设置delegate
        keyboardManager.delegate = self
        keyboardManager.dataSource = self
        // 将输入条View添加到ViewController；
        // true：表示输入条平时不显示（比如朋友圈）；
        // false：表示平时也显示（比如聊天）
        keyboardManager.addBottomInputBarView(inputBarView: inputBoxView, belowViewController: true)
        // 把输入框（如果有的话）绑定给管理类
        keyboardManager.bindTextView(inputTextView: inputBoxView.inputTextView)
        
    }
    
    // 其代表屏幕的哪些边缘不需要首先响应系统手势——有上下左右4个边缘可选。
    public override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge {
        xLog("preferredScreenEdgesDeferringSystemGestures")
        return .bottom
    }
}

extension ZegoUIKitPrebuiltLiveStreamingVC: IMChatInputBoxViewDelegate {
    
    func inputBox(inputBox: IMChatInputBoxView, updateHeight height: CGFloat, isSendText: Bool) {
        // 输入框的高度发生了改变（因为输入框里的文字行数变化了），注意这里仅仅是TextView输入框的高度发生了变化的回调；
        // isText：YES表示是因为调用了clearInputTextBySend去发送文本
        keyboardManager.inputTextViewHeightDidChange(becauseSendText: isSendText)
    }
    
    func inputBox(inputBox: IMChatInputBoxView, onKeyboardSendClick inputNormalText: String) {
        xLog("发送 内容 【\(inputNormalText)】")
        var text = inputNormalText.replacingOccurrences(of: " ", with: "")
        text = text.replacingOccurrences(of: "\n", with: "")
        if text.isEmpty {
            // 只有空格和回车的消息不允许发送
            return
        }
        
        YLHUD.showLottie()
        // 元组 (from, to)
        let language = UserProfile.country == 0 ? ("zh", "ru"): ("ru", "zh")
        NeoNuiTranslation.translation(from: language.0, to: language.1, text: text) { sourceText, result in
            DispatchQueue.main.async {
                YLHUD.hideHUD()
                if let dst = result {
                    ZegoUIKit.shared.sendInRoomMessage("\(text)（\(dst)）") { [weak self] errorCode in
                        xLog("发送消息 :\("\(text)（\(dst)）") errorCode: \(errorCode)")
                        self?.inputBoxView.clearAll()
                        self?.inputBoxView.setTextViewFirstResponder(false)
                    }
                    
                } else {
                    ZegoUIKit.shared.sendInRoomMessage(text) { [weak self] errorCode in
                        xLog("翻译失败 发送消息 errorCode: \(errorCode)")
                        self?.inputBoxView.clearAll()
                        self?.inputBoxView.setTextViewFirstResponder(false)
                    }
                }
            }
        }
    }
    
    func inputBoxDidSeleteItem(itemType: IMChatInputBoxViewItemType, sender: UIButton) {
        
    }
    
    func inputBoxStartRecording(isSuccess: Bool) {
        
    }
    
    func inputBoxEndRecording(recordFinish recordFileUrl: String, duration: Int) {
        
    }
}

// MARK: - 评论输入框
// MARK: InputBoardDelegate, InputBoardDataSource
extension ZegoUIKitPrebuiltLiveStreamingVC: InputBoardDelegate, InputBoardDataSource {
    func extendBoardView(keyboardManager: InputBoxManager) -> UIView {
        UIView()
    }
    
    func emoticonBoardView(keyboardManager: InputBoxManager) -> UIView {
        UIView()
    }
    
    func extendBoardHeight(keyboardManager: InputBoxManager) -> CGFloat {
        0
    }
    
    func emoticonBoardHeight(keyboardManager: InputBoxManager) -> CGFloat {
        0
    }
}

// MARK: - 实时翻译
extension ZegoUIKitPrebuiltLiveStreamingVC {
    
    // 开启实时传译
    func startRealtimeTranslation() {
        xLog("开启实时传译")
        
        if useIFlyASR {
            // 使用科大讯飞实时语音转写
            startIFlyASR()
        } else {
            // 使用阿里语音转写（现有方式）
            startAliASR()
        }
    }
    
    // 结束实时传译
    func stopRealtimeTranslation() {
        xLog("关闭实时传译")
        
        if useIFlyASR {
            // 停止科大讯飞实时语音转写
            stopIFlyASR()
        } else {
            // 停止阿里语音转写
            stopAliASR()
        }
    }
    
    // 开启科大讯飞实时语音转写
    private func startIFlyASR() {
        xLog("开启科大讯飞实时语音转写")
        
        iflyASRManager = IFlyRealTimeASRManager.shared
        iflyASRManager?.delegate = self
        iflyASRManager?.setLanguage(LanguageManager.isCountryCN ? .chinese : .russian)
        
        // 开始音频数据采集
        startAudioDataObserver()
        
        // 开始识别
        let success = iflyASRManager?.startRealTimeASR() ?? false
        if success {
            xLog("科大讯飞实时语音转写启动成功")
        } else {
            xLog("科大讯飞实时语音转写启动失败")
        }
    }
    
    // 停止科大讯飞实时语音转写
    private func stopIFlyASR() {
        xLog("停止科大讯飞实时语音转写")
        iflyASRManager?.stopRealTimeASR()
        stopAudioDataObserver()
        iflyASRManager = nil
    }
    
    // 开启阿里语音转写（现有方式）
    private func startAliASR() {
        xLog("开启阿里语音转写")
        NeoNuiManager.shared().initNeoNui(LanguageManager.isCountryCN ? .zh: .ru, delegate: self)
        NeoNuiManager.shared().startAudioDataObserver()
    }
    
    // 停止阿里语音转写
    private func stopAliASR() {
        xLog("停止阿里语音转写")
        NeoNuiManager.shared().stopAudioDataObserver()
    }
    
    // 处理翻译结果（通用方法）
    private func handleTranslationResult(_ model: IMRecvSeiModel) {
        // 添加到消息列表
        messages.append(model)
        
        // 更新翻译视图
        translationView.updateContent(number: coHostList.count, hostId: currentHost?.userID ?? "", model: model)
        
        // 发送SEI消息
        ZegoUIKit.shared.sendInRoomMessage(model.toJSONString()!) { errorCode in
            if errorCode == 1009013 {
                // 消息输入长度超出限制
                xLog("[Zego] 消息输入长度超出限制")
            }
        }
    }
    
    // 开始音频数据采集
    private func startAudioDataObserver() {
        // 需要的音频数据类型 Bitmask，此处示例四个回调都开启
        let bitmask: ZegoAudioDataCallbackBitMask = [.captured, .player]
        // 需要的音频数据参数，此处示例单声道、16 K
        let param = ZegoAudioFrameParam()
        param.channel = .mono
        param.sampleRate = .rate16K
        
        // 开启获取原始音频数据功能
        ZegoExpressEngine.shared().startAudioDataObserver(bitmask, param: param)
        // 设置音频数据回调
        ZegoExpressEngine.shared().setAudioDataHandler(self)
    }
    
    // 停止音频数据采集
    private func stopAudioDataObserver() {
        // 异步停止，避免阻塞调用线程
        DispatchQueue.global(qos: .userInitiated).async {
            ZegoExpressEngine.shared().stopAudioDataObserver()
        }
    }
}

extension ZegoUIKitPrebuiltLiveStreamingVC: NeoNuiDelegate {
    public func neoNuiRealtimeTranslation(_ text: String, languageType: NeoNuiLanguageType, isEnd: Bool) {
        
        // xLog("主播 id \(currentHost?.userID ?? "kong")")
//        if let hostId = currentHost?.userID, hostId != String(UserProfile.userId) {
//            if coHostList.count > 2 {
//                xLog("连麦人数大于 2 的时候, 连麦人说的话不做翻译发出去")
//                return
//            }
//        }
        
        /// 被主播关闭了
        if !isAllowedTranslation {
            return
        }
        
        // if !isEnd { return }
        if text.isEmpty { return }
        
        xLog("neoNuiSpeechTranscriberResult: \(text)")
        
        let language = languageType == .zh ? ("zh", "ru"): ("ru", "zh")
        
        NeoNuiTranslation.translation(from: language.0, to: language.1, text: text) { [weak self] sourceText, result in
            if let result = result {
                let model = IMRecvSeiModel()
                model.type = "1"
                model.text = text
                model.trans = result
                model.userId = String(UserProfile.userId)
                model.username = UserProfile.username
                model.usernameRu = UserProfile.usernameRu
                
                // 使用通用方法处理翻译结果
                self?.handleTranslationResult(model)
            }
        }
    }
    
    public func neoNuiRmsChanged(_ rms: Float) {
        
    }
    
    public func neoNuiRealtimeTranslationEnd(_ isFinish: Bool) {
        
    }
    
}

// MARK: - 科大讯飞实时语音转写代理
extension ZegoUIKitPrebuiltLiveStreamingVC: IFlyRealTimeASRDelegate {
    
    func realTimeASRDidBegin() {
        xLog("科大讯飞实时语音转写开始")
    }
    
    func realTimeASRDidEnd() {
        xLog("科大讯飞实时语音转写结束")
    }
    
    func realTimeASRDidFail(_ error: Error) {
        xLog("科大讯飞实时语音转写失败: \(error.localizedDescription)")
    }
    
    func realTimeASRDidReceiveResult(_ result: String, isLast: Bool) {
        xLog("科大讯飞实时语音转写结果: \(result), 是否最后结果: \(isLast)")
        
        if result.isEmpty { return }
        
        // 检查是否允许翻译
        if !isAllowedTranslation {
            return
        }
        
        // 无论是中间结果还是最终结果，都进行翻译（类似阿里语音识别）
        let fromLanguage = LanguageManager.isCountryCN ? "zh" : "ru"
        let toLanguage = LanguageManager.isCountryCN ? "ru" : "zh"
        
        NeoNuiTranslation.translation(from: fromLanguage, to: toLanguage, text: result) { [weak self] sourceText, translatedText in
            guard let weakSelf = self else { return }
            
            let model = IMRecvSeiModel()
            model.type = "1"
            model.text = result
            model.trans = translatedText ?? "机翻失败"
            model.userId = String(UserProfile.userId)
            model.username = UserProfile.username
            model.usernameRu = UserProfile.usernameRu
            
            // 处理翻译结果
            weakSelf.handleTranslationResult(model)
        }
    }
    
    func realTimeASRDidComplete(_ error: Error?) {
        if let error = error {
            xLog("科大讯飞实时语音转写完成，错误: \(error.localizedDescription)")
        } else {
            xLog("科大讯飞实时语音转写完成")
        }
    }
    
    func realTimeASRConnectionStateChanged(_ isConnected: Bool) {
        xLog("科大讯飞实时语音转写连接状态: \(isConnected ? "已连接" : "已断开")")
    }
    
}

// MARK: - ZegoAudioDataHandler
extension ZegoUIKitPrebuiltLiveStreamingVC: ZegoAudioDataHandler {
    
    public func onCapturedAudioData(_ data: UnsafePointer<UInt8>, dataLength: UInt32, param: ZegoAudioFrameParam) {
        // 本地采集音频数据，推流后可收到回调
        let sendData = Data(bytes: data, count: Int(dataLength))
        
        // 如果使用科大讯飞实时语音转写，发送音频数据
        if useIFlyASR {
            iflyASRManager?.sendAudioData(sendData)
        }
    }
    
}
